package com.myzl.coal.client.parse;

import com.myzl.coal.client.CacheData;
import com.myzl.coal.client.config.LocalCommunicationParse;
import com.myzl.coal.domain.AlarmEvent;
import com.myzl.coal.domain.dto.RealTimeDataDTO;
import com.myzl.coal.dto.CmdCallBackDTO;
import com.myzl.coal.dto.SendCmdDTO;
import com.myzl.coal.mongo.component.MongoComponent;
import com.myzl.coal.mq.MqService;
import com.myzl.coal.service.IAgreementContrastService;
import com.myzl.coal.service.IRealTimeDataService;
import com.myzl.coal.service.protocol.CmdService;
import com.myzl.common.constant.DeviceConstants;
import com.myzl.common.constant.ProtocolConstants;
import com.myzl.common.enums.AlarmEventType;
import com.myzl.common.enums.DeviceTypeEnum;
import com.myzl.common.enums.SensorEnum;
import io.netty.channel.ChannelHandler;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import static com.myzl.coal.utils.HexUtil.*;


/**
 * @author 91941
 */
@Component
@ChannelHandler.Sharable
@Slf4j(topic = "admin-collect")
@Data
@LocalCommunicationParse(deviceType = DeviceConstants.SIEVE_PLC)
public class SievePlcParse extends CommonParseService {

    private final IAgreementContrastService agreementContrastService;
    private final IRealTimeDataService realTimeDataService;
    private final CmdService cmdService;
    private final CacheData cacheData;
    private final MqService mqService;
    private final MongoComponent mongoComponent;


    /**
     * 客户端发消息会触发
     */
    @Override
    public void channelRead(Object msg, Integer deviceId) {
        try {
            byte[] dataBytes = (byte[]) msg;
            String dataStr = bytesToHexString(dataBytes);
            log.info(this.getClass().getSimpleName() + " receive Data:{}", dataStr);

            String num = getString(dataBytes, 0, 2);
            int length = getInt(dataBytes, 4, 2);
            int deviceNum = getInt(dataBytes, 6, 1);
            int fun = getInt(dataBytes, 7, 1);
            int lenAfter = getInt(dataBytes, 8, 1);

            SendCmdDTO sendCmdDTO = cmdService.getSendCmd(deviceId, num);

            CmdCallBackDTO cmdCallBackDTO = new CmdCallBackDTO();
            if (!Objects.isNull(sendCmdDTO)) {
                BeanUtils.copyProperties(sendCmdDTO, cmdCallBackDTO);
            }
            cmdCallBackDTO.setStatus(false);
            cmdCallBackDTO.setCallBackCmd(dataStr);

            switch (fun) {
                case 03:
                    if (dataBytes.length > 50) {
                        String dataValue = "";
                        SensorEnum[] enums = SensorEnum.values();
                        parseData(deviceId, dataBytes, enums);

                    }else {
                        SensorEnum[] enums = {SensorEnum.MOTOR_SET};
                        parseData(deviceId, dataBytes, enums);
                    }
                    cmdCallBackDTO.setStatus(true);
                    storageData(mqService,DeviceTypeEnum.SIEVE_PLC);
                case 05:
                case 16:
                    cmdCallBackDTO.setStatus(true);
                    break;
                case 0x83:
                case 0x85:
                default:
                    cmdCallBackDTO.setStatus(false);
            }
            if (!Objects.isNull(sendCmdDTO)) {
                cmdService.success(cmdCallBackDTO);
            }

        } catch (Exception e) {
            log.info("receive data error:", e);
        }
    }

    private void parseData(Integer deviceId, byte[] dataBytes, SensorEnum[] enums) {
        String dataValue;
        Map<Integer, BigDecimal> policeValue = new HashMap<>();
        for (int i = 0, j = 9; i < enums.length; i++) {
            SensorEnum e = enums[i];
            switch (e.getDataType()) {
                case ProtocolConstants.DATATYPE_FLOAT:
                    int dataIntValue = getInt(dataBytes, j, e.getNumber() * 2);
                    float toFloat = Float.intBitsToFloat(dataIntValue);
                    dataValue = new BigDecimal(toFloat).setScale(2, RoundingMode.HALF_UP).toString();
                    break;
                case ProtocolConstants.DATATYPE_INT:
                default:
                    dataIntValue = getInt(dataBytes, j, e.getNumber() * 2);
                    dataValue = Integer.toString(dataIntValue);
                    break;
            }

            switch (e) {
                case MOTOR_TEMPERATURE:
                    policeValue.put(SensorEnum.MOTOR_TEMPERATURE_POLICE.getAddress(), new BigDecimal(dataValue));
                    break;
                case EXCITER_TEMPERATURE:
                    policeValue.put(SensorEnum.EXCITER_TEMPERATURE_POLICE.getAddress(), new BigDecimal(dataValue));
                    break;
                case MOTOR_TEMPERATURE_POLICE:
                case EXCITER_TEMPERATURE_POLICE:
                    AlarmEvent alarmEvent = new AlarmEvent();
                    alarmEvent.setDictValue(e.getAddress());
                    alarmEvent.setDeviceId(deviceId);
                    alarmEvent.setEventType(AlarmEventType.SIEVE.getCode());
                    if (Objects.equals(dataValue, "1") || Objects.equals(dataValue, "1.00")) {
                        alarmEvent.setTitle("筛机运行状态报警");
                        alarmEvent.setContent(e.getInfo());
                        alarmEvent.setAlarmValue(policeValue.get(e.getAddress()));
                        alarmEvents.add(alarmEvent);
                    }else {
                        restore.add(alarmEvent);
                    }
                    break;
                default:
            }
            j = j + e.getNumber() * 2;

            RealTimeDataDTO realTimeData = new RealTimeDataDTO();
            realTimeData.setDeviceId(deviceId);
            realTimeData.setDictValue(e.getAddress());
            realTimeData.setDataUnit(e.getUnit());
            realTimeData.setDeviceType(DeviceTypeEnum.SIEVE_PLC.getCode());
            realTimeData.setDataValue(dataValue);
            realTimeDataList.add(realTimeData);
        }
    }


    @Override
    public void initConnect(Integer deviceId) {
    }
}
